using System;
using System.Collections.Generic;
using System.Text;

using Microsoft.Xna.Framework;

namespace HadronData
{
    public struct Transformation
    {
        private static Transformation s_trnIdentity = new Transformation(0.0f);

        private Vector2 m_vecRotation;
        private Vector2 m_vecTranslation;

        public static Transformation Identity
        {
            get { return s_trnIdentity; }
        }

        public Transformation(Transformation p_transformation)
        {
            m_vecRotation = p_transformation.m_vecRotation;
            m_vecTranslation = p_transformation.m_vecTranslation;
        }

        public Transformation(float p_fOrientation, Vector2 p_vecTranslation)
        {
            m_vecRotation.X = (float)Math.Cos(p_fOrientation);
            m_vecRotation.Y = (float)Math.Sin(p_fOrientation);
            m_vecTranslation = p_vecTranslation;
        }

        public Transformation(float p_fOrientation)
        {
            m_vecRotation.X = (float)Math.Cos(p_fOrientation);
            m_vecRotation.Y = (float)Math.Sin(p_fOrientation);
            m_vecTranslation = Vector2.Zero;
        }

        public Transformation(Vector2 p_vecTranslation)
        {
            m_vecRotation = Vector2.UnitX;
            m_vecTranslation = p_vecTranslation;
        }

        public Vector2 Apply(Vector2 p_vecPoint)
        {
            return new Vector2(
                p_vecPoint.X * m_vecRotation.X - p_vecPoint.Y * m_vecRotation.Y + m_vecTranslation.X,
                p_vecPoint.X * m_vecRotation.Y + p_vecPoint.Y * m_vecRotation.X + m_vecTranslation.Y);
        }

        public Transformation ComposeWith(Transformation p_trnInner)
        {
            return new Transformation(
                this.Rotation + p_trnInner.Rotation,
                Apply(p_trnInner.Translation));
        }

        public float Rotation
        {
            get { return (float)Math.Atan2(m_vecRotation.Y, m_vecRotation.X); }
            set
            {
                m_vecRotation.X = (float)Math.Cos(value);
                m_vecRotation.Y = (float)Math.Sin(value);
            }
        }

        public Vector2 RotationDirection
        {
            get { return m_vecRotation; }
            set
            {
                m_vecRotation = value;
                m_vecRotation.Normalize();
            }
        }

        public Vector2 Translation
        {
            get { return m_vecTranslation; }
            set { m_vecTranslation = value; }
        }

        public Transformation Inverse
        {
            get
            {
                Transformation trnInverse = new Transformation();
                trnInverse.m_vecRotation.X = m_vecRotation.X;
                trnInverse.m_vecRotation.Y = -m_vecRotation.Y;
                trnInverse.Translation = trnInverse.Apply(-m_vecTranslation);
                return trnInverse;
            }
        }

        public Transformation RotationComponent
        {
            get
            {
                Transformation trnRotation = new Transformation();
                trnRotation.m_vecRotation = m_vecRotation;
                return trnRotation;
            }
        }

        public Transformation TranslationComponent
        {
            get
            {
                Transformation trnTranslation = new Transformation();
                trnTranslation.m_vecTranslation = m_vecTranslation;
                return trnTranslation;
            }
        }
    }
}
